package layers.agents;

import java.util.ArrayList;

import layers.ants.AntTickListener;
import layers.ants.DeliveryAnt;
import layers.ants.IntentionAnt;
import layers.ants.PackageAnt;
import layers.physical.Crossroad;
import layers.physical.Package;
import layers.physical.Path;
import events.packageEvents.PackagePickedUpEvent;
import framework.events.EventBroker;

public class PackageAgent implements AntTickListener, AgentInterface{

	private static final int INTENTION_EVAPORATION_TICKS = 500;
	private final int TURNOVERCOUNT = 250;
	private int ticksLeft = 0;
	private Package pack;
	private Path deliveryPath;
	private int hops = DeliveryAnt.INITIALHOPS;

	/**
	 * The the shortest ETA from a truck so far. This value is not decremented,
	 *  so the distance traveled by the truck between the sending of two intention ants.
	 *  This is because the difference is very small.
	 */
	private long bestETA;

	/**
	 * Number of ticks the current best ETA will last
	 */
	private int etaTicksleft;
	private boolean pathFound = false;

	public PackageAgent(Package pack){
		this.pack = pack;
	}

	protected Package getPackage(){
		return this.pack;
	}

	public Crossroad getDestination(){
		return this.getPackage().getDestination();
	}

	/**
	 *  - manage packageants
	 *  - evaporate best ETA
	 */
	public void processAntTick() {
		if (ticksLeft == 0) {
			managePackageAnts();
			manageDeliveryAnts();
			ticksLeft = TURNOVERCOUNT;
		}
		ticksLeft--;
		evaporateETA();
	}

	private void manageDeliveryAnts() {
//		if(!pathFound ){
		if(deliveryPath == null){
			new DeliveryAnt(this.getPackage().getOrigin(),
					this.getPackage().getDestination(), 
					this, null, this.getHops(), 0);
			this.increaseHops();
		}
//		if(deliveryPath != null)
//			pathFound = true;
	}

	/**
	 * the ETA lasts for 2 x the time it took for the corresponding intention ant to get here
	 */
	private void evaporateETA() {
		etaTicksleft--;
		if(etaTicksleft <= 0)
			bestETA = Long.MAX_VALUE;
	}

	/**
	 * choose best from this vs bestETA
	 * @return This intention has been accepted
	 */
	public boolean processIntention(IntentionAnt ant) {
		if(ant.getTotalDistance() <= bestETA){
			bestETA = ant.getTotalDistance();
			etaTicksleft = INTENTION_EVAPORATION_TICKS;
			return true;
		}
		return false;
	}

	public int getBestETA(ArrayList<Integer> etas) {
		int best = Integer.MAX_VALUE;
		for(int eta : etas)
			if (eta>best) 
				best = eta;
		return best;
	}

	protected void managePackageAnts() {
		new PackageAnt(pack.getOrigin(), 0, null, this);
	}

	public void notifyOfPickup() {
		this.getPackage().getOrigin().removePackage();
		EventBroker.getEventBroker().notifyAll(new PackagePickedUpEvent(this.getPackage().getId(), this, this.getPackage().getDestination().getPosition()));
	}

	public String toString(){
		return ""+this.getPackage().getId();
	}

	@Override
	public int getId() {
		return this.getPackage().getId();
	}

	public void proposeDelivery(Path path) {
		if(this.deliveryPath == null)
			this.deliveryPath = path;
		else if(deliveryPath.getTotalDistance()>path.getTotalDistance())
			deliveryPath = path;
	}

	protected Path getDeliveryPath() {
		return deliveryPath;
	}


	protected int getHops() {
		return hops;
	}

	protected void increaseHops(){
		this.hops *= 2;
		if(this.hops > 200)
			this.hops = 200;
	}

	public int getPackageId() {
		return this.getPackage().getId();
	}
}
